package com.consumer.common;

import com.alibaba.fastjson.JSONObject;

import com.consumer.config.MinioConfig;
import com.consumer.entity.FileUploadResponse;
import io.minio.*;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Component
public class MinioUtil {
    @Resource
    private MinioConfig minioProp;

    private MinioClient client;

    /**
     * 初始化minio配置
     */
    @PostConstruct
    public void init() {
        try {
            client = MinioClient.builder().endpoint(minioProp.getEndpoint()).credentials(minioProp.getAccessKey(), minioProp.getSecretKey()).build();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("初始化minio配置异常: 【{}】", e.fillInStackTrace());
        }
    }

    /**
     * 创建bucket
     * true -> 存在，直接返回false
     * false -> 不存在，创建bucketName
     */
    public Boolean createBucket(@IdConstraint String bucketId) throws Exception {
        if (checkBucket(bucketId)) {
            System.out.println(bucketId + "已创建");
            return false;
        } else {
            client.makeBucket(MakeBucketArgs.builder().bucket(bucketId).build());
            System.out.println(bucketId + "正在创建");
            return true;
        }
    }

    /**
     * 判断是否存在bucketName
     * true -> 存在
     * false -> 不存在
     *
     * @param bucketId
     * @return
     * @throws Exception
     */
    public Boolean checkBucket(@IdConstraint String bucketId) throws Exception {
        return client.bucketExists(BucketExistsArgs.builder().bucket(bucketId).build());
    }

    /**
     * 创建目录
     *
     * @param bucketName
     * @param dir
     * @return
     */
    public Boolean createDir(@NotNull String bucketName, @NotNull String dir) {
        if (!bucketName.isEmpty()) {
            bucketName = bucketName.toLowerCase();
        }
        Boolean re = false;
        try {
            client.putObject(PutObjectArgs.builder().bucket(bucketName).object(dir).stream(new ByteArrayInputStream(new byte[]{}), 0, -1).build());
            re = true;
        } catch (Exception e) {
            e.printStackTrace();
            re = false;
        }
        return re;
    }

    /**
     * 查询 bucket下的文件信息
     *
     * @param bucket
     * @return
     */
    public List<Object> selectBucketInfo(String bucket) {
        Iterable<Result<Item>> results = client.listObjects(ListObjectsArgs.builder().bucket(bucket).build());
        String format = "{'fileName':'%s','fileSize':'%s'}";
        List<Object> relist = new ArrayList<>();
        results.forEach(i -> {
            try {
                String name = i.get().objectName();
                long size = i.get().size();
                String info = String.format(format, name, size);
                JSONObject jsonObject = JSONObject.parseObject(info);
                relist.add(jsonObject);
            } catch (Exception ex) {

            }
        });
        return relist;
    }

    /**
     * 上传文件
     */
    public FileUploadResponse uploadFile(MultipartFile file, String bucketName, String fullName) throws Exception {
        if (!bucketName.isEmpty()) {
            bucketName = bucketName.toLowerCase();
        }
        //判断文件是否为空
        if (null == file) {
            return null;
        }
        //文件名
        String originalFilename = file.getOriginalFilename();
        //新的文件名 = 存储桶文件名_时间戳.后缀名
        assert originalFilename != null;
        if (StringUtils.isEmpty(fullName)) {
            fullName = originalFilename;
        }
        //开始上传
        client.putObject(PutObjectArgs.builder().bucket(bucketName).object(fullName).stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build());
        String url = minioProp.getEndpoint() + "/" + bucketName + fullName;
        String urlHost = minioProp.getHost() + "/" + bucketName + fullName;
        log.info("上传文件成功url ：[{}], urlHost ：[{}]", url, urlHost);
        return new FileUploadResponse(url, urlHost);
    }

    /**
     * 上传文件
     */
    public void uploadMultiFiles(MultipartFile file, String bucketId, String fullName) throws Exception {
        //判断文件是否为空
        if (!bucketId.isEmpty()) {
            bucketId = bucketId.toLowerCase();
        }
        //判断存储桶是否存在  不存在则创建
        createBucket(bucketId);
        //文件名
        String originalFilename = file.getOriginalFilename();
        //新的文件名 = 存储桶文件名_时间戳.后缀名
        assert originalFilename != null;
        //SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        if (StringUtils.isEmpty(fullName)) {
            fullName = originalFilename;
        }
        //开始上传
        client.putObject(PutObjectArgs.builder().bucket(bucketId).object(fullName).stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build());
    }
//    /**
//     * 获取全部bucket
//     *
//     * @return
//     */
//    public List<Bucket> getAllBuckets() throws Exception {
//        return client.listBuckets();
//    }
//
//    /**
//     * 根据bucketName获取信息
//     *
//     * @param bucketName bucket名称
//     */
//    public Optional<Bucket> getBucket(String bucketName) throws Exception {
//        return client.listBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();
//    }

    /**
     * 根据bucketName删除信息
     *
     * @param bucketName bucket名称
     */
    public void removeBucket(String bucketName) throws Exception {
        client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
    }

    /**
     * 获取⽂件外链
     *
     * @param bucketName bucket名称
     * @param objectName ⽂件名称
     * @param expires    过期时间 <=7
     * @return url
     */
    public String getObjectURL(String bucketName, String objectName, Integer expires) throws Exception {
        return client.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().bucket(bucketName).object(objectName).expiry(expires).build());
    }

    /**
     * 获取⽂件
     *
     * @param bucketName bucket名称
     * @param objectName ⽂件名称
     * @return ⼆进制流
     */
    public InputStream getObject(String bucketName, String objectName) throws Exception {
        if (bucketName.isEmpty()) {
            bucketName = bucketName.toLowerCase();
        }
        return client.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
    }

    /**
     * 上传⽂件
     *
     * @param bucketName bucket名称
     * @param objectName ⽂件名称
     * @param stream     ⽂件流
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject
     */
    public void putObject(String bucketName, String objectName, InputStream stream) throws Exception {
        if (!bucketName.isEmpty()) {
            bucketName = bucketName.toLowerCase();
        }
        client.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(stream, stream.available(), -1).contentType(objectName.substring(objectName.lastIndexOf("."))).build());
    }

    /**
     * 上传⽂件
     *
     * @param bucketName  bucket名称
     * @param objectName  ⽂件名称
     * @param stream      ⽂件流
     * @param size        ⼤⼩
     * @param contextType 类型
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject
     */
    public void putObject(String bucketName, String objectName, InputStream stream, long size, String contextType) throws Exception {
        if (!bucketName.isEmpty()) {
            bucketName = bucketName.toLowerCase();
        }
        client.putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(stream, size, -1).contentType(contextType).build());
    }

    /**
     * 获取⽂件信息
     *
     * @param bucketName bucket名称
     * @param objectName ⽂件名称
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#statObject
     */
    public StatObjectResponse getObjectInfo(String bucketName, String objectName) throws Exception {
        if (!bucketName.isEmpty()) {
            bucketName = bucketName.toLowerCase();
        }
        return client.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
    }

    /**
     * 删除⽂件
     *
     * @param bucketName bucket名称
     * @param objectName ⽂件名称
     * @throws Exception https://docs.minio.io/cn/java-client-apireference.html#removeObject
     */
    public void removeObject(String bucketName, String objectName) throws Exception {

        client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
    }

    /**
     * 下载文件
     *
     * @param bucketId
     * @param filename
     * @return
     */
    public ResponseEntity<byte[]> downloadFile(@NotNull String bucketId, @NotNull String bucketFileUrl, String filename, HttpServletResponse response) {
        ResponseEntity<byte[]> responseEntity = null;
        try {
            // 创建MinIO客户端
            // 获取文件流
            GetObjectResponse objectResponse = client.getObject(GetObjectArgs.builder().bucket(bucketId) // 替换为你实际的存储桶名称
                    .object(bucketFileUrl).build());
            int len = -1;
            byte[] buffer = new byte[1024];
            FastByteArrayOutputStream outputStream = new FastByteArrayOutputStream();
            while ((len = objectResponse.read(buffer)) != -1) outputStream.write(buffer, 0, len);
            outputStream.flush();
            byte[] bytes = outputStream.toByteArray();
            // 设置响应头
            HttpHeaders headers = new HttpHeaders();
//            headers.add(HttpHeaders.CONTENT_TYPE, objectResponse.contentType());
            headers.add("Accept-Ranges", "bytes");
            //把文件名按UTF-8取出并按ISO8859-1编码，保证弹出窗口中的文件名中文不乱码，中文不要太多，最多支持17个中文，因为header有150个字节限制。
            headers.add("Content-disposition", "attachment; filename=" + filename);
            headers.add("Content-Type", "text/plain;charset=utf-8");
//            return ResponseEntity.ok().headers(headers).body(new InputStreamResource(inputStream));

            responseEntity = new ResponseEntity<byte[]>(bytes, headers, HttpStatus.CREATED);
        } catch (Exception e) {
            return ResponseEntity.notFound().build();
        }
        return responseEntity;
    }


    public void copyObject(String srcBucket, String srcObject, String destBucket, String destObject) {
        try {
            client.copyObject(CopyObjectArgs.builder()
                    .source(CopySource.builder()
                            .bucket(srcBucket)
                            .object(srcObject)
                            .build())
                    .bucket(destBucket)
                    .object(destObject)
                    .build());
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}
